using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;

namespace MKDS_Course_Editor.GCN.BMD
{
    class EVP1
    {
        public class Evp1Header
        {
            public string tag; //'EVP1'
            public UInt32 sizeOfSection;
            public UInt16 count;
            public UInt16 pad;

            //0 - count many bytes, each byte describes how many bones belong to this index
            //1 - sum over all bytes in 0 many shorts (index into some joint stuff? into matrix table?)
            //2 - bone weights table (as many floats as shorts in 1)
            //3 - matrix table (matrix is 3x4 float array)
            public UInt32[] offsets = new UInt32[4];
        }
        public class MultiMatrix
        {
            public List<float> weights = new List<float>();
            public List<UInt16> indices = new List<ushort>(); //indices into Evp1.matrices (?)
        }

        public class Evp1
        {
            public List<MultiMatrix> weightedIndices = new List<MultiMatrix>();
            public List<LibNDSFormats.NSBMD.MTX44> matrices = new List<LibNDSFormats.NSBMD.MTX44>();
        }

        private static void readEvp1Header(EndianBinaryReader er, Evp1Header h)
        {
            h.tag = er.ReadString(Encoding.ASCII, 4);
            h.sizeOfSection = er.ReadUInt32();
            h.count = er.ReadUInt16();
            h.pad = er.ReadUInt16();
            for (int i = 0; i < 4; ++i)
            {
                h.offsets[i] = er.ReadUInt32();
            }
        }

        private static void readArray8(EndianBinaryReader er, List<int> arr)
        {
            for (int i = 0; i < arr.Count; ++i)
            {
                byte v = er.ReadByte();
                arr[i] = v;
            }
        }

        private static void readMatrix(EndianBinaryReader er, float[][] m)
        {
            m = new float[3][];
            for (int j = 0; j < 3; ++j)
            {
                m[j] = new float[4];
                for (int k = 0; k < 4; ++k)
                {
                    m[j][k] = (float)er.ReadSingle();
                    //Helper.toFLOAT(m[j][k]);
                }
            }
        }

        public static void dumpEvp1(EndianBinaryReader er, Evp1 dst)
        {
            int evp1Offset = (int)er.BaseStream.Length, i;

            //read header
            Evp1Header h = new Evp1Header();
            readEvp1Header(er, h);

            //read counts array
            er.BaseStream.Position = evp1Offset + h.offsets[0];
            List<int> counts = new List<int>();
            counts.AddRange(new int[h.count]);
            readArray8(er, counts);

            //read indices of weighted matrices
            dst.weightedIndices.AddRange(new MultiMatrix[h.count]);
            er.BaseStream.Position = evp1Offset + h.offsets[1];
            int numMatrices = 0;
            for (i = 0; i < h.count; ++i)
            {
                dst.weightedIndices[i].indices.AddRange(new ushort[counts[i]]);
                for (int j = 0; j < counts[i]; ++j)
                {
                    UInt16 d = er.ReadUInt16(); Helper.toWORD(d);
                    dst.weightedIndices[i].indices[j] = d;
                    numMatrices = Helper.max(numMatrices, d + 1);
                }
            }

            //read weights of weighted matrices
            er.BaseStream.Position = evp1Offset + h.offsets[2];
            for (i = 0; i < h.count; ++i)
            {
                dst.weightedIndices[i].weights.AddRange(new float[counts[i]]);
                for (int j = 0; j < counts[i]; ++j)
                {
                    float fl = (float)er.ReadInt32(); Helper.toFLOAT(fl);
                    dst.weightedIndices[i].weights[j] = fl;
                }
            }

            //read matrices
            dst.matrices.AddRange(new LibNDSFormats.NSBMD.MTX44[numMatrices]);
            er.BaseStream.Position = evp1Offset + h.offsets[3];
            for (i = 0; i < numMatrices; ++i)
            {
                float[][] m = new float[3][];
                readMatrix(er, m);

                LibNDSFormats.NSBMD.MTX44 dMat = dst.matrices[i];
                for (int j = 0; j < 3; ++j)
                {
                    for (int k = 0; k < 4; ++k)
                        dMat[j, k] = m[j][k];
                }
                dMat[3, 0] = 0.0f; dMat[3, 1] = 0.0f; dMat[3, 2] = 0.0f; dMat[3, 3] = 1.0f;
            }
        }

    }
}
